package info.niwota.web.apache;

import info.niwota.commons.io.Files;
import info.niwota.web.ApplicationContext;
import info.niwota.web.Debug;
import info.niwota.web.NVPair;
import info.niwota.web.Utils;

import java.io.File;
import java.io.IOException;
import java.io.InputStream;
import java.io.UnsupportedEncodingException;
import java.net.URLEncoder;
import java.util.ArrayList;
import java.util.Iterator;
import java.util.List;

import x.org.apache.commons.fileupload.FileItem;
import x.org.apache.commons.fileupload.HttpServletRequest;
import x.org.apache.commons.fileupload.disk.DiskFileItemFactory;
import x.org.apache.commons.fileupload.servlet.ServletFileUpload;
import x.org.apache.http.Header;
import x.org.apache.http.HttpEntity;
import x.org.apache.http.HttpEntityEnclosingRequest;
import x.org.apache.http.HttpException;
import x.org.apache.http.HttpRequest;
import x.org.apache.http.HttpRequestInterceptor;
import x.org.apache.http.protocol.HttpContext;
import x.org.apache.http.util.EntityUtils;
import android.content.Context;
import android.text.TextUtils;
import android.util.Log;

/**
 * @author qiangli
 * 
 */
public class RequestParametersInterceptor implements HttpRequestInterceptor {
	private static final String URL_ENCTYPE = "application/x-www-form-urlencoded";
	private static final String DATA_ENCTYPE_PREFIX = "multipart/form-data";
	
	private static final String TAG = "RequestParametersInterceptor";
	
	private File tempDir;

	public RequestParametersInterceptor(Context ctx) {
		tempDir = ApplicationContext.getTempDir(ctx);
	}

	public void process(HttpRequest request, HttpContext context)
			throws HttpException, IOException {
		//skip proxy request
		if (HttpUtils.isProxy(context)) {
			return;
		}
		
		List<NVPair> params = new ArrayList<NVPair>();
		final String charset = "UTF-8";

		final String requestUri = request.getRequestLine().getUri();
		Utils.parseUri(params, requestUri, charset);
		if (request instanceof HttpEntityEnclosingRequest) {
			HttpEntity entity = ((HttpEntityEnclosingRequest) request)
					.getEntity();
			
			if (Debug.DEBUG) {
				Log.d(TAG, "entity: " + entity);
			}
			
			if (entity != null) {
				Header th = entity.getContentType();
				if (th == null || URL_ENCTYPE.equals(th.getValue())) {
					Header eh = entity.getContentEncoding();
					String encoding = charset;
					if (eh != null) {
						encoding = eh.getValue();
					}
					String c = EntityUtils.toString(entity);
					Utils.parseContent(params, c, encoding);
				} else if (th.getValue().startsWith(DATA_ENCTYPE_PREFIX)) {
					// long len = entity.getContentLength();
					// if (len > 0 && len < MAX_INLINE_DATA_LEN) {
					// byte[] c = EntityUtils.toByteArray(entity);
					// }

					InputStream is = entity.getContent();
					// 
					DiskFileItemFactory factory = new DiskFileItemFactory();
					factory.setSizeThreshold(1);

					factory.setRepository(tempDir);
					ServletFileUpload upload = new ServletFileUpload(factory);
					upload.setSizeMax(-1);
					//
					HttpServletRequest req = new HttpServletRequest();
					req.inputStream = is;
					req.characterEncoding = getValue(entity
							.getContentEncoding());
					req.contentLength = entity.getContentLength();
					req.contentType = getValue(entity.getContentType());
					List<FileItem> items = upload.parseRequest(req);
					Iterator<FileItem> it = items.iterator();
					while (it.hasNext()) {
						FileItem item = (FileItem) it.next();
						if (item.isFormField()) {
							processFormField(item, params);
						} else {
							processUploadedFile(item, params);
							context.setAttribute(BaseHandler.FIX_JSON_KEY, "true");
						}
					}
				}
				//
				EntityUtils.consume(entity);
			}
		}
		if (params.size() > 0) {
			context.setAttribute(BaseHandler.PARAMETERS_KEY, params);
		}
	}

	private void processFormField(FileItem item, List<NVPair> params) {
		String name = item.getFieldName();
		String value = item.getString();
		params.add(new NVPair(name, value));
	}

	private void processUploadedFile(FileItem item, List<NVPair> params)
			throws IOException {
		final String fn = item.getFieldName();
		final String name = item.getName();
		
		if (Debug.DEBUG) {
			Log.d(TAG, "file uploaded: " + name + " field name: " + fn);
		}
		
		File uploadedFile = File.createTempFile("uploaded-", fn+Files.CAMOUFLAGE, tempDir);
		
		if (Debug.DEBUG) {
			Log.d(TAG, "save to : " + uploadedFile);
		}
		
		item.write(uploadedFile);
		
		//
//		//blueimp
//		final long length = uploadedFile.length();
//		//send relative file name only
//		final String vpath = "/" + uploadedFile.getName();
//		final String furi = "file:" + vpath;
//		final long length = uploadedFile.length();
//		//
//		params.add(new NVPair("name", name));
//		params.add(new NVPair("type", item.getContentType()));
//		params.add(new NVPair("size", Files.formatSize(length)));
//		params.add(new NVPair("length", uploadedFile.length()+""));
//		params.add(new NVPair("uri", furi));
//		params.add(new NVPair("path", uploadedFile.getName()));
		//
		final String path = uploadedFile.getPath();
		params.add(new NVPair(fn + ".name", encode(name)));
		params.add(new NVPair(fn + ".type", item.getContentType()));
		params.add(new NVPair(fn + ".path", encode(path)));
		//
		if (Debug.DEBUG) {
			Log.d(TAG, "upload file saved: len: " + uploadedFile.length() + " path: " + path +" file: " + uploadedFile);
		}
	}

	private String encode(String v) throws UnsupportedEncodingException {
		return TextUtils.isEmpty(v) ? null : URLEncoder.encode(v, "UTF-8");
	}

	private String getValue(Header h) {
		return (h == null ? null : h.getValue());
	}
}
